﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace eVision.SharpSort.Core
{
    /// <summary>
    /// Provides utility methods to guard parameter and local variables.
    /// </summary>
    public class Guard
    {
        private const Exception nullException = null;

        /// <summary>
        /// Throws an exception of type <typeparamref name="TException"/> with the specified message
        /// when the assertion statement is true.
        /// </summary>
        /// <typeparam name="TException">The type of exception to throw.</typeparam>
        /// <param name="assertion">The assertion to evaluate. If true then the <typeparamref name="TException"/> exception is thrown.</param>
        /// <param name="message">string. The exception message to throw.</param>
        public static void Against<TException>(bool assertion, string message) where TException : Exception
        {
            if (assertion)
                throw (TException)Activator.CreateInstance(typeof(TException), message);
        }

        public static void IsNotNull(Object target, string message)
        {
            IsNotNull<NullReferenceException>(target, message);
        }

        public static void IsNotNull<TException>(Object target, string message) where TException : Exception
        {
            if (target == null)
                throw (TException)Activator.CreateInstance(typeof(TException), message);
        }

        public static void StringIsNotNullOrEmpty(String target, string message)
        {
            if (target == null)
                throw new ArgumentNullException(message, nullException);
            if(string.CompareOrdinal(target, String.Empty) == 0)
                throw new ArgumentOutOfRangeException(message, nullException);
        }

        /// <summary>
        /// Throws an exception of type <typeparamref name="TException"/> with the specified message
        /// when the assertion
        /// </summary>
        /// <typeparam name="TException"></typeparam>
        /// <param name="assertion"></param>
        /// <param name="message"></param>
        public static void Against<TException>(Func<bool> assertion, string message) where TException : Exception
        {
            //Execute the lambda and if it evaluates to true then throw the exception.
            if (assertion())
                throw (TException)Activator.CreateInstance(typeof(TException), message);
        }

        /// <summary>
        /// Throws a <see cref="InvalidCastException"/> when the specified object
        /// instance is not castable to <typeparamref name="TBase"/> type.
        /// </summary>
        /// <typeparam name="TBase">The base type to check for.</typeparam>
        /// <param name="instance">The object to check if it inherits from <typeparamref name="TBase"/> type.</param>
        /// <param name="message">string. The exception message to throw.</param>
        public static void IsCastable<TBase>(object instance, string message)
        {
            if (!(instance is TBase))
                throw new InvalidCastException(message);
        }

        /// <summary>
        /// Throws an exception if an instance of an object is not equal to another object instance.
        /// </summary>
        /// <typeparam name="TException">The type of exception to throw when the guard check evaluates false.</typeparam>
        /// <param name="compare">The comparison object.</param>
        /// <param name="instance">The object instance to compare with.</param>
        /// <param name="message">string. The message of the exception.</param>
        public static void IsEqual<TException>(object compare, object instance, string message) where TException : Exception
        {
            if (compare != instance)
                throw (TException)Activator.CreateInstance(typeof(TException), message);
        }
    }
}
